VGA-Kurs - Part #2 Moin! Hier, nun und jetzt, wie zu erwarten "T.C.P.s' Beginner's Guide To VGA Coding"(TM), Part II! Wie schon im ersten Teil gesagt, werde ich diese Serie nur fortsetzen, wenn sich auch genug Leute melden, mich mit Lob besudeln, mit Klagen zuballern oder mir einfach ein paar Tips geben. Na dann, aufi gaits Buam! Heute wollen wir uns einem wichtigen und fr Anf„nger oft sehr verwirrenden Kapitel der VGA-Programmierung zuwenden: Der VGA-Palette! Aber erst dies: Ihr erinnert euch doch bestimmt an unsere "optimierte" PutPixel-Routine aus der ersten Ausgabe; Sie schrieb die Pixelwerte direkt in den Bildschirmspeicher und war so bedeutend schneller als die Bios-Variante. Wollen mal sehen, ob wir nicht noch ein paar Clocks rausquetschen k”nnen: procedure PutPixel(x,y:integer; col:byte);assembler; asm mov ax,0A000h mov es,ax mov bx,[x] mov dx,[y] mov di,bx mov bx,dx shl dx,8 shl bx,6 add dx,bx add di,dx mov al,[col] stosb end; (Hinweis: Fr diese Prozedur mát ihr entweder im Compiler-Optionsmen die 286er-Code Erzeugung aktivieren (oder am Anfang des Programms den Compiler-Schalter {$G+} setzen) oder statt "shl dx,8" 8 mal "shl dx" und statt "shl bx,6" 6 mal "shl bx" schreiben.) Um den Sinn dieser Prozedur auf Anhieb zu verstehen, muá man schon etwas mehr Erfahrung haben: Als erstes wird (wie wahrscheinlich noch alle erkannt haben) die Adresse des VGA-Segments nach ES geMOVt (Manche werden wissen, daá das Register-Paar ES:DI einen Zeiger darstellt, und nun in DI das Offset des gewnschten Pixels stehen muá). Anschlieáend kommt die Adresse von x bzw. y nach BX bzw. DX. Nun wird (nachdem x nach BX nach DI und DX nach BX verschoben wurde, der Inhalt von DX (y) nun also in BX und DX ist) der Wert in DX um 8 (entspricht einer Multiplikation mit 256) und der in BX um 6 (entspricht Mult. mit 64) nach links geshiftet. Dann werden die beiden addiert, und was haben wir jetzt? Y mult. mit 320! (Teuflisch, nicht?) Dazu wird nun der Wert von X addiert, dann die Farbe nach AL gebracht und STOSB aufgerufen. Schon haben wir den Pixel dort, wo wir ihn haben wollten! So, nun zu den Paletten. Wie wohl jeder weiá, hat man im Modus 13h 256 Farben zur Verfgung. Ausw„hlen kann man diese 256 Farben aber aus einem Bereich von 262144 verschiedenen Farbt”nen. Nun, die Standard-Auswahl ("Palette") der VGA-Farben ist nicht sehr klug gew„hlt und oft findet man die Farbe, die man braucht, nicht in dieser Auswahl. Also, wie beschafft man sich neue? Vorerst einmal ein paar Grundlagen (Ich weiá, Theorie ist Bullshit, aber sie muá trotzdem sein). Ihr habt bestimmt in der Schule mal gelernt, daá Farbt”ne aus den drei Grundfarben entstehen: Rot, Grn (eigentlich Gelb) und Blau (Wenn nicht, wiát ihr es sp„testens jetzt). Dadurch lassen sich theoretisch endlos viele Farben herstellen (die aber eigentlich niemand braucht ;-), indem man ebendiese Farben zu bestimmten Anteilen miteinander vermischt. Aber was hat das jetzt mit der VGA-Palette zu tun? Ganz einfach, sie basiert auf demselben Prinzip! Wenn man weiá wie, kann man sich ber 260000 neue Farbt”ne erstellen! Aber wie? Jede unserer 256 Standard-VGA-Farben besteht schon aus diesen 3 Farbwerten. Die Farbe 0 z.B. ist schwarz und besteht somit aus den Werten (0,0,0), also: 0 Rot, 0 Grn, 0 Blau. Farbe 31 dagegen (weiá) hat die Werte (63,63,63), also die Maximalwerte jedes Farbtons. So sind nun s„mtliche Farben aufgebaut. Wenn man ein tiefes Blau hat (0,0,63), kann man es aufhellen, indem man die Werte fr Rot und Grn heraufsetzt (32,32,63). Erh”ht man dagegen nur den Wert fr Rot, erh„lt man ein dunkleres Blau bis Lila. So, nun zum praktischen Teil: Wie setze ich die Palettenwerte einer Farbe? procedure SetPal(col,R,G,B:byte); begin port[$3C8] := col; port[$3C9] := R; port[$3C9] := G; port[$3C9] := B; end; Hier wird erst dem DAC-Port(3C8h) die Nummer der Farbe zugewiesen, um ihn auf einen Schreibzugriff vorzubereiten. Anschlieáend werden die 3 Farbwerte an den Port 3C9h abgeschickt, und -zack!- sitzen die neuen Werte in der Palette. Dies ist sehr ntzlich, weil alle Farben der Nummer col auf einen Schlag eine neue Farbe bekommen, was man trickreich ausnutzen kann. Ein Beiástiel: Die Palettenmanipulation wird oft in Adventures eingesetzt, wenn in einer Location ein Wasserfall simuliert werden soll. Dieser wird erst gezeichnet, und anschlieáend werden die Werte der Farben des Wasserfalls (meist Blaut”ne) st„ndig miteinander verstauscht, so daá es aussieht, als wrde wirklich Wasser flieáen. Aufwendige Animationen, die Speicherplatz verschwenden, bleiben einem erspart (Diese Methode nennt sich brigens Colorcycling). Es gibt noch mehr Anwendungsbeispiele, von denen wir einige besprechen werden. Allerdings hat diese Pal-Manipulation einen Nachteil: Es entsteht ein Flackern, was nun wirklich unsch”n ist. Vermieden werden kann es, indem man vorher diese Prozedur callt: procedure WaitRetrace;assembler; asm mov dx,3DAh @x: in al,dx test al,08h jnz @x @y: in al,dx test al,08h jz @y end; Folgendes: Der Bildschirm wird alle soundsoviele Millisekunden wieder neu aufgebaut: "Retraced". Wird nun w„hrend eines solchen Retrace das Bild irgendwie ver„ndert, so entsteht ein st”rendes Flackern. Dies kann vermieden werden, indem man vor JEDER wichtigen Bildschirm„nderung (Sprite zeichnen, Palette ver„ndern, etc.) den Retrace abwartet. Die Prozedur "weckt" das Input Status Register 1 der VGA und sieht nach, wie das Bit 3 aussieht. Es zeigt n„mlich an, wie es um den Retrace steht. Die Prozedur wird solange geloopt, bis der Retrace unten am Bildschirm angelangt ist, dann beendet, worauf man die Palette ver„ndern kann. Alles klar? Ach brigens: Man kann die Palette auch auslesen: procedure GetPal(col:byte; var R,G,B:byte); begin port[$3C7] := col; R := port[$3C9]; G := port[$3C9]; B := port[$3C9]; end; Mit dieser Prozedur kann man die Farbwerte der Farbe col ermitteln. So, war da nicht die Rede von anderen Anwendungsgebieten der Pal-Mod.? Hier etwas sehr trickreiches: Wenn man nicht will, daá der Anwender sieht, was man mit der VGA anstellt, kann man das auch "unsichtbar" machen. Man setzt einfach s„mtliche Farben auf Schwarz: procedure BlackPal; var n : byte; begin WaitRetrace; for n := 0 to 255 do SetPal(n,0,0,0); end; Allerdings sollte man vorher seine Palettenwerte sichern, sonst kann man das Bild schlecht wiederherstellen. Dazu deklarieren wir eine globale Variable Pal : array[0..255,1..3] of byte. Das Sichern der Palette: procedure GrabPal; var n : byte; begin for n := 0 to 255 do GetPal(n,Pal[n,1],Pal[n,2], Pal[n,3]); end; Dies schreibt s„mtliche Palettenwerte in das Array Pal. Wollen wir nun alle Werte wieder herstellen, brauchen wir eine neue Prozedur namens RestorePal, fr die ihr einfach das GetPal in ein SetPal verwandelt und nach dem "begin" ein "waitretrace" einfgt. Nachdem man die Palette mit GrabPal gerettet, den Bildschirm mittels BlackPal abgedunkelt und das Bild (was auch immer das sein mag) auf den VGA "geklatscht" hat, kann man auch eine andere, effektvollere Art des Einblendens w„hlen, als einfach die Palette wiederherzustellen: Fading! Fading ist ein Paletteneffekt, den man sehr oft zu sehen bekommt. Er funktioniert folgendermaáen: Nachdem man die oben beschriebenen Schritte durchgefhrt hat und der Bildschirm schwarz ist, schreibt man die gewnschte Zielpalette in die Variable Pal und erh”ht nun solange schrittweise die Palettenwerte, bis die Zielwerte in Pal erreicht sind. Das geht so: procedure FadeUp; var n1,n2 : byte; Tmp : array[1..3] of byte; begin for n1 := 1 to 64 do begin WaitRetrace; For n2 := 0 to 255 do begin GetPal(n2,Tmp[1],Tmp[2],Tmp[3]); if Tmp[1] < Pal[n2,1] then inc (Tmp[1]); if Tmp[2] < Pal[n2,2] then inc (Tmp[2]); if Tmp[3] < Pal[n2,3] then inc (Tmp[3]); SetPal(n2,Tmp[1],Tmp[2],Tmp[3]); end; end; end; Bei dieser Prozedur wird zun„chst der Retrace abgewartet. Anschlieáend wird fr jede Farbe berprft, ob ihre Farbwerte schon denen in der Zielpalette entsprechen. Wenn nicht, wird der Wert um 1 erh”ht. Danach wird der neue Wert in die Palette eingetragen. Das Ganze wird 64 mal wiederholt. Umgekehrt geht auch. Will man also ein Bild auf dem VGA langsam ausfaden, schreibt man sich eine Prozedur wie oben, nur ersetzt man die INCs durch DECs, die Kleiner-als- durch Gr”áer-als-Zeichen, und die "Pal[n2,?]" durch 0. So, nun k”nnen wir schon ein paar sehr sch”ne Effekte erzielen, vielleicht k”nnt ihr aus den vorgegebenen Routinen noch mehr machen (z.B ein Fading ins Weiáe erzeugt den Eindruck einer Explosion). Ich hoffe ich werde in dem PCH, in dem diese Anzi erscheint schon eine Menge Feedback lesen. N„chstes Thema ist h”chstwahrscheinlich...Scrollinx!!! Na dann, bis zur n„chsten Ausgabe. [ This text copyright (c) 1995-96 Johannes Spohr. All rights reserved. ] [ Distributed exclusively through PC-Heimwerker, Verlag Thomas Eberle. ] [ ] [ No part of this document may be reproduced, transmitted, ] [ transcribed, stored in a retrieval system, or translated into any ] [ human or computer language, in any form or by any means; electronic, ] [ mechanical, magnetic, optical, chemical, manual or otherwise, ] [ without the expressed written permission of the author. ] [ ] [ The information contained in this text is believed to be correct. ] [ The text is subject to change without notice and does not represent ] [ a commitment on the part of the author. ] [ The author does not make a warranty of any kind with regard to this ] [ material, including, but not limited to, the implied warranties of ] [ merchantability and fitness for a particular purpose. The author ] [ shall not be liable for errors contained herein or for incidental or ] [ consequential damages in connection with the furnishing, performance ] [ or use of this material. ]